home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / MSJV7_2B.ARJ / DOC.C < prev    next >
C/C++ Source or Header  |  1992-03-01  |  17KB  |  590 lines

  1. /*
  2.   OLE SERVER DEMO           
  3.   Doc.c             
  4.                                                                      
  5.   This file contains document methods and various document-related support 
  6.   functions.
  7.                                                                      
  8.   (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved   
  9. */                                                                     
  10.  
  11. /* 
  12.    Important Note:
  13.  
  14.    No method should ever dispatch a DDE message or allow a DDE message to
  15.    be dispatched.
  16.    Therefore, no method should ever enter a message dispatch loop.
  17.    Also, a method should not show a dialog or message box, because the 
  18.    processing of the dialog box messages will allow DDE messages to be
  19.    dispatched.
  20. */
  21.  
  22.  
  23.  
  24. #define SERVERONLY
  25. #include "Windows.h"
  26. #include "Ole.h"
  27. #include "SrvrDemo.h"
  28.  
  29. /* AssociateClient
  30.  * ---------------
  31.  *
  32.  * Add a client to the list of clients associated with an object.
  33.  *
  34.  * This function is necessary only because ServerDemo does not create object
  35.  * structures as they are requested, but rather has a fixed set of objects.
  36.  * When DocGetObject is called with a NULL object name, the entire 
  37.  * document is requested, but ServerDemo does not currently support making
  38.  * the entire document an object, so DocGetObject returns one object.
  39.  * That object now goes by two names: NULL and its real name.  Therefore
  40.  * we need to keep track of both lpoleclient's that were passed to 
  41.  * DocGetObject.  Ideally, DocGetObject should always create a new OBJ 
  42.  * structure containing a pointer (or some reference) to the object's native
  43.  * data and also containing one lpoleclient.
  44.  *
  45.  * LPOLECLIENT lpoleclient - the client to be associated with the object.
  46.  * LPOBJ lpobj             - the object 
  47.  *
  48.  * RETURNS: TRUE if successful
  49.  *          FALSE if out of memory
  50.  *
  51.  * CUSTOMIZATION: Server Demo specific
  52.  *
  53.  */
  54. static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
  55. {
  56.    int i;
  57.    for (i=0; i < clpoleclient; i++)
  58.    {
  59.       if (lpobj->lpoleclient[i]==lpoleclient)
  60.       {
  61.          return TRUE;
  62.       }
  63.       if (lpobj->lpoleclient[i]==NULL)
  64.       {
  65.          lpobj->lpoleclient[i]=lpoleclient;
  66.          return TRUE;
  67.       }
  68.    }
  69.    return FALSE;
  70. }
  71.  
  72.  
  73.  
  74. /* CreateNewDoc
  75.  * ------------
  76.  *
  77.  * If lhdoc == NULL then we must register the new document by calling
  78.  * OleRegisterServerDoc, which will return a new handle which will be stored
  79.  * in docMain.lhdoc.
  80.  * Also if lhdoc==NULL then this document is being created at the request of
  81.  * the user, not of the client library.
  82.  *
  83.  * LONG lhdoc      - Document handle
  84.  * LPSTR lpszDoc   - Title of the new document
  85.  * DOCTYPE doctype - What type of document is being created
  86.  * 
  87.  * RETURNS: TRUE if successful, FALSE otherwise.
  88.  *
  89.  * CUSTOMIZATION: Re-implement
  90.  *
  91.  */
  92. BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
  93. {
  94.    int i;
  95.  
  96.    // Fill in the fields of the document structure.
  97.    if (lhdoc == NULL)
  98.    {
  99.       if (OLE_OK != OleRegisterServerDoc 
  100.                      (srvrMain.lhsrvr, 
  101.                       lpszDoc,
  102.                       (LPOLESERVERDOC) &docMain, 
  103.                       (LHSERVERDOC FAR *) &docMain.lhdoc))
  104.          return FALSE;
  105.    }
  106.    else
  107.       docMain.lhdoc = lhdoc;
  108.  
  109.    docMain.doctype      = doctype;
  110.    docMain.oledoc.lpvtbl= &docvtbl;
  111.    // Reset all the flags because no object numbers have been used.
  112.    for (i=1; i <= cfObjNums; i++)
  113.       docMain.rgfObjNums[i] = FALSE;
  114.  
  115.    fDocChanged = FALSE;
  116.  
  117.    SetTitle (lpszDoc, doctype == doctypeEmbedded);
  118.    return TRUE;
  119. }
  120.  
  121.  
  122.  
  123. /* DestroyDoc
  124.  * ----------
  125.  *
  126.  * Free all memory that had been allocated for a document.
  127.  *
  128.  *
  129.  * CUSTOMIZATION: Re-implement.  Your application will probably use some
  130.  *                other method for enumerating all the objects in a document.
  131.  *                ServerDemo enumerates the child windows, but if each object 
  132.  *                does not have its own window, this will not work.
  133.  *
  134.  */
  135. void DestroyDoc (void)
  136. {
  137.    HWND hwnd;
  138.    HWND hwndNext;
  139.  
  140.    // Delete all object windows.  
  141.    hwnd = SelectedObjectWindow();
  142.    while (hwnd) 
  143.    {
  144.       hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
  145.       // Each object window frees its own memory upon receiving WM_DESTROY.
  146.       DestroyWindow (hwnd);
  147.       hwnd = hwndNext;
  148.    } 
  149.  
  150.    if (docMain.aName)
  151.    {
  152.       GlobalDeleteAtom (docMain.aName);
  153.       docMain.aName = NULL;
  154.    }
  155.  
  156.    if (docMain.hpal)
  157.       DeleteObject (docMain.hpal);
  158. }
  159.  
  160.  
  161.  
  162. /* DocClose                DOCUMENT "Close" METHOD
  163.  * --------
  164.  *
  165.  * The library calls this method to unconditionally close the document.
  166.  *
  167.  * LPOLESERVERDOC lpoledoc - The server document to close
  168.  * 
  169.  * RETURNS: Return value from RevokeDoc.
  170.  *
  171.  * CUSTOMIZATION: None
  172.  *
  173.  */
  174. OLESTATUS FAR PASCAL DocClose (LPOLESERVERDOC lpoledoc)
  175. {
  176.    return RevokeDoc();
  177. }
  178.  
  179.  
  180.  
  181. /* DocExecute                DOCUMENT "Execute" METHOD
  182.  * ----------
  183.  *
  184.  * This application does not support the execution of DDE execution commands.
  185.  * 
  186.  * LPOLESERVERDOC lpoledoc - The server document
  187.  * HANDLE hCommands        - DDE execute commands
  188.  * 
  189.  * RETURNS: OLE_ERROR_COMMAND
  190.  *
  191.  * CUSTOMIZATION: Re-implement if your application supports the execution of
  192.  *                DDE commands.
  193.  *
  194.  */
  195. OLESTATUS FAR PASCAL DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
  196. {
  197.    return OLE_ERROR_COMMAND;
  198. }
  199.  
  200.  
  201.  
  202. /* DocGetObject                DOCUMENT "GetObject" METHOD
  203.  * ------------
  204.  *
  205.  * The library uses this method to get an object's structure for the
  206.  * client.  Memory needs to be allocated and initialized here for this.
  207.  * A NULL string indicates that the client has an embedded object
  208.  * which was started from Create, CreateFromTemplate, or Edit, but not Open.
  209.  *
  210.  * First see if the object name is NULL.  If so, you would ordinarily
  211.  * return the entire document, but Server Demo returns the selected object.
  212.  * If the object name is not NULL, then go through the list of objects, 
  213.  * searching for one with that name.  Return an error if there is not one.
  214.  *
  215.  * LPOLESERVERDOC lpoledoc        - The server document
  216.  * LPSTR lpszObjectName           - The name of the object to get data for
  217.  * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
  218.  * LPOLECLIENT lpoleclient        - The client structure
  219.  * 
  220.  * RETURNS:        OLE_OK
  221.  *                 OLE_ERROR_NAME if object not found
  222.  *                 OLE_ERROR_MEMORY if no more memory to store lpoleclient
  223.  *
  224.  * CUSTOMIZATION: Re-implement.
  225.  *                lpszObjectName == "" indicates that the whole document 
  226.  *                should be the object returned.
  227.  *
  228.  */
  229. OLESTATUS FAR PASCAL DocGetObject
  230.    (LPOLESERVERDOC lpoledoc, LPSTR lpszObjectName, 
  231.     LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
  232. {
  233.     HWND  hwnd;
  234.     ATOM  aName;
  235.     LPOBJ lpobj;
  236.  
  237.  
  238.     if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
  239.     {   
  240.         // Return a new object or the selected object.
  241.         hwnd = SelectedObjectWindow();
  242.         lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
  243.         *lplpoleobject = (LPOLEOBJECT) lpobj;
  244.         // Associate client with object.
  245.         if (!AssociateClient (lpoleclient, lpobj))
  246.             return OLE_ERROR_MEMORY;
  247.         return OLE_OK;
  248.     }
  249.  
  250.     if (!(aName = GlobalFindAtom (lpszObjectName)))
  251.         return OLE_ERROR_NAME;
  252.  
  253.     hwnd = SelectedObjectWindow();
  254.  
  255.     // Go through all the child windows and find the window whose name
  256.     // matches the given object name.
  257.  
  258.     while (hwnd)
  259.     {
  260.          lpobj = HwndToLpobj (hwnd);
  261.  
  262.          if (aName == lpobj->aName)
  263.          {
  264.             // Return the object with the matching name.
  265.             *lplpoleobject = (LPOLEOBJECT) lpobj;
  266.             // Associate client with the object.
  267.             if (!AssociateClient (lpoleclient, lpobj))
  268.                return OLE_ERROR_MEMORY;
  269.             return OLE_OK;
  270.          }
  271.          hwnd = GetWindow (hwnd, GW_HWNDNEXT);
  272.     }
  273.  
  274.    if (((DOCPTR)lpoledoc)->doctype ==  doctypeEmbedded)
  275.    {
  276.       lpobj = CreateNewObj (FALSE);
  277.       *lplpoleobject = (LPOLEOBJECT) lpobj;
  278.       
  279.       // Associate client with object.
  280.       if (!AssociateClient (lpoleclient, lpobj))
  281.          return OLE_ERROR_MEMORY;
  282.       return OLE_OK;
  283.     }
  284.  
  285.     // Object with name lpszObjName was not found.
  286.     return OLE_ERROR_NAME;
  287. }
  288.  
  289. /* DocRelease                DOCUMENT "Release" METHOD
  290.  * ----------
  291.  *
  292.  * The library uses this method to notify the server that a revoked
  293.  * document has finally finished all conversations, and can be 
  294.  * destroyed.
  295.  * It sets fWaitingForDocRelease to FALSE so a new document can be created
  296.  * and the user can continue working.
  297.  *
  298.  * LPOLESERVERDOC lpoledoc        - The server document
  299.  * 
  300.  * RETURNS: OLE_OK
  301.  *
  302.  * CUSTOMIZATION: None
  303.  *
  304.  */
  305. OLESTATUS FAR PASCAL DocRelease (LPOLESERVERDOC lpoledoc)
  306. {
  307.    fWaitingForDocRelease = FALSE;
  308.    // Free all memory that has been allocated for the document.
  309.    DestroyDoc();
  310.  
  311.    return OLE_OK;
  312. }
  313.  
  314.  
  315.  
  316. /* DocSave                DOCUMENT "Save" METHOD
  317.  * -------
  318.  *
  319.  * Save document to a file.
  320.  *
  321.  * LPOLESERVERDOC lpoledoc - The document to save
  322.  * 
  323.  * RETURNS: OLE_OK
  324.  *
  325.  * CUSTOMIZATION: None
  326.  *
  327.  */
  328. OLESTATUS FAR PASCAL DocSave (LPOLESERVERDOC lpoledoc)
  329. {
  330.     if (docMain.doctype == doctypeFromFile)
  331.     {
  332.          // No "File Save As" dialog box will be brought up because the
  333.          // file name is already known.
  334.          return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
  335.     }
  336.     else
  337.       return OLE_ERROR_GENERIC;
  338. }
  339.  
  340.  
  341.  
  342. /* DocSetDocDimensions        DOCUMENT "SetDocDimensions" METHOD
  343.  * -------------------
  344.  *
  345.  * The library calls this method to tell the server the bounds on
  346.  * the target device for rendering the document.
  347.  * A call to this method is ignored for linked objects because the size of
  348.  * a linked document depends only on the source file.
  349.  *
  350.  * LPOLESERVERDOC lpoledoc - The server document
  351.  * LPRECT         lprect   - The target size in MM_HIMETRIC units
  352.  * 
  353.  * RETURNS: OLE_OK
  354.  *
  355.  * CUSTOMIZATION: Re-implement
  356.  *                How an object is sized is application-specific. (Server Demo
  357.  *                uses MoveWindow.)
  358.  *                     
  359.  */
  360. OLESTATUS FAR PASCAL DocSetDocDimensions 
  361.    (LPOLESERVERDOC lpoledoc, LPRECT lprect)
  362. {
  363.    if (docMain.doctype == doctypeEmbedded)
  364.    {
  365.       RECT rect = *lprect;
  366.       
  367.       // the units are in HIMETRIC
  368.       rect.right   = rect.right - rect.left;
  369.       rect.bottom  = rect.top - rect.bottom;
  370.       HiMetricToDevice (hwndMain, (LPPOINT) &rect.right);
  371.       MoveWindow (SelectedObjectWindow(), 0, 0, 
  372.                   rect.right + 2 * GetSystemMetrics(SM_CXFRAME), 
  373.                   rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME), 
  374.                   TRUE);
  375.       /* If for some reason your application needs to notify the client that
  376.          the data has changed because DocSetDocDimensions has been called,
  377.          then notify the client here.
  378.          SendDocMsg (OLE_CHANGED);
  379.       */
  380.    }
  381.    return OLE_OK;
  382. }
  383.  
  384.  
  385.  
  386. /* DocSetHostNames        DOCUMENT "SetHostNames" METHOD
  387.  * ---------------
  388.  *
  389.  * The library uses this method to set the name of the document
  390.  * window.
  391.  * All this function does is change the title bar text, although it could
  392.  * do more if necesary. 
  393.  * This function is only called for embedded objects; linked objects
  394.  * use their filenames for the title bar text.
  395.  *
  396.  * LPOLESERVERDOC lpoledoc    - The server document
  397.  * LPSTR lpszClient           - The name of the client
  398.  * LPSTR lpszDoc              - The client's name for the document
  399.  * 
  400.  * RETURNS:        OLE_OK
  401.  * 
  402.  * CUSTOMIZATION: None
  403.  *
  404.  */
  405. OLESTATUS FAR PASCAL DocSetHostNames 
  406.    (LPOLESERVERDOC lpoledoc, LPSTR lpszClient, LPSTR lpszDoc)
  407. {
  408.    SetTitle (lpszDoc, TRUE);
  409.    lstrcpy ((LPSTR) szClient, lpszClient);
  410.    lstrcpy ((LPSTR) szClientDoc, Abbrev(lpszDoc));
  411.    UpdateFileMenu (IDM_UPDATE);   
  412.    return OLE_OK;
  413. }
  414.  
  415.  
  416.  
  417. /* DocSetColorScheme                DOCUMENT "SetColorScheme" METHOD
  418.  * -----------------
  419.  *
  420.  * The client calls this method to suggest a color scheme (palette) for
  421.  * the server to use.
  422.  * In Server Demo the document's palette is never actually used because each 
  423.  * object has its own palette.  See ObjSetColorScheme.
  424.  *
  425.  * LPOLESERVERDOC lpoledoc - The server document
  426.  * LPLOGPALETTE   lppal    - Suggested palette
  427.  *
  428.  * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails, 
  429.  *          OLE_OK otherwise
  430.  *
  431.  * 
  432.  * CUSTOMIZATION: If your application supports color schemes, then this 
  433.  *                function is a good example of how to create and store
  434.  *                a palette.
  435.  */
  436. OLESTATUS FAR PASCAL DocSetColorScheme 
  437.    (LPOLESERVERDOC lpoledoc, LPLOGPALETTE lppal)
  438. {
  439.    HPALETTE hpal = CreatePalette (lppal);
  440.  
  441.    if (hpal==NULL)
  442.       return OLE_ERROR_PALETTE;
  443.  
  444.    if (docMain.hpal) 
  445.    {
  446.       // Delete old palette
  447.       DeleteObject (docMain.hpal);
  448.    }
  449.    // Store handle to new palette
  450.    docMain.hpal = hpal;
  451.    return OLE_OK;
  452. }
  453.  
  454.  
  455.  
  456. /* RevokeDoc
  457.  * ---------
  458.  *
  459.  * Call OleRevokeServerDoc.
  460.  * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
  461.  * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
  462.  * As long as fWaitingForDocRelease is set, the user interface will be 
  463.  * disabled so that the user will not be able to manipulate the document.
  464.  * When the DocRelease method is called, it will reset fWaitingForDocRelease,
  465.  * allowing RevokeDoc to free the document's memory and return.
  466.  *
  467.  * This is essentially a way to make an asynchronous operation synchronous.
  468.  * We need to wait until the old document is revoked before we can delete
  469.  * its data and create a new one.
  470.  *
  471.  * Note that we cannot call RevokeDoc from a method because it is illegal to
  472.  * enter a message-dispatch loop within a method.
  473.  *
  474.  * RETURNS: The return value of OleRevokeServerDoc.
  475.  *
  476.  * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your 
  477.  *                application does not have a global variable corresponding 
  478.  *                to docMain.
  479.  * 
  480.  */
  481. OLESTATUS RevokeDoc (void)
  482. {
  483.    OLESTATUS olestatus;
  484.  
  485.    if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
  486.       DestroyDoc();
  487.  
  488.    docMain.lhdoc = NULL; // A NULL handle indicates that the document 
  489.                          // has been revoked or is being revoked.
  490.    return olestatus;
  491.  
  492. }
  493.  
  494.  
  495.  
  496. /* SaveChangesOption
  497.  * -----------------
  498.  *
  499.  * Give the user the opportunity to save changes to the current document
  500.  * before continuing.
  501.  *
  502.  * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
  503.  *                       the update and needs to be updated when the document
  504.  *                       is closed.  In that case, OLE_CLOSED will be sent.
  505.  *
  506.  * RETURNS: IDYES, IDNO, or IDCANCEL
  507.  *
  508.  * CUSTOMIZATION: None
  509.  *
  510.  */
  511. int SaveChangesOption (BOOL *pfUpdateLater)
  512. {
  513.    int  nReply;
  514.    char szBuf[cchFilenameMax];
  515.    
  516.    *pfUpdateLater = FALSE;
  517.    
  518.    if (fDocChanged)
  519.    {
  520.        char szTmp[cchFilenameMax];
  521.        
  522.        if (docMain.aName) 
  523.            GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
  524.        else 
  525.            szTmp[0] = NULL;
  526.  
  527.        if (docMain.doctype == doctypeEmbedded)
  528.            wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));        
  529.        else
  530.            lstrcpy (szBuf, (LPSTR) "Save changes?");         
  531.      
  532.        nReply = MessageBox (hwndMain, szBuf, szAppName, 
  533.                       MB_ICONEXCLAMATION | MB_YESNOCANCEL);
  534.                   
  535.        switch (nReply)
  536.        {
  537.           case IDYES:
  538.               if (docMain.doctype != doctypeEmbedded)
  539.                   SaveDoc();
  540.               else
  541.                   switch (OleSavedServerDoc (docMain.lhdoc))
  542.                   {
  543.                       case OLE_ERROR_CANT_UPDATE_CLIENT:
  544.                           *pfUpdateLater = TRUE;
  545.                           break;
  546.                       case OLE_OK:
  547.                           break;
  548.                       default:
  549.                           ErrorBox ("Fatal Error: Cannot update.");
  550.                   }                                      
  551.               return IDYES;
  552.           case IDNO:
  553.               return IDNO;
  554.          case IDCANCEL:
  555.               return IDCANCEL;
  556.        }
  557.    }
  558.    return TRUE;
  559. }
  560.  
  561.  
  562.  
  563. /* SendDocMsg
  564.  * ----------
  565.  *
  566.  * This function sends messages to all the objects in a document when
  567.  * the document has changed.
  568.  *
  569.  * WORD wMessage - The message to send
  570.  * 
  571.  * CUSTOMIZATION: The means of enumerating all the objects in a document
  572.  *                is application specific.
  573.  */
  574. void SendDocMsg (WORD wMessage)
  575. {
  576.     HWND    hwnd;
  577.  
  578.     // Get handle to first object window.
  579.     hwnd = SelectedObjectWindow();
  580.  
  581.     // Send message to all object windows.
  582.     while (hwnd)
  583.     {
  584.         SendObjMsg (HwndToLpobj(hwnd), wMessage);
  585.         hwnd = GetWindow (hwnd, GW_HWNDNEXT);
  586.     }
  587. }
  588.  
  589.  
  590.